/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tallerfinal.controller;

import java.lang.reflect.InvocationTargetException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import tallerfinal.model.InventoryModel;
import tallerfinal.model.InventoryModelFactory;
import tallerfinal.util.distributions.MersenneTwisterFast;

/**
 *
 * @author ricardo
 */
public class OptimizationController {

    private InventoryModel model;
    private ArrayList<Tuple> tabuList;

    public OptimizationController(InventoryModel model) {
        this.model = model;
        tabuList = new ArrayList<>();
    }

    public OptimizationController(int id, Object... params) {
        try {
            model = InventoryModelFactory.getInstance().createGenerator(id, params);
            tabuList = new ArrayList<>();
        } catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException ex) {
            Logger.getLogger(OptimizationController.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private ArrayList<Tuple> Neighbors(int A, int B) {
        if (model == null || tabuList == null) {
            return null;
        }
        ArrayList<Tuple> neighbors = new ArrayList<>();
        int a = A;
        int b = B;
        if (A % 2 != 0) {
            a += 1;
        }
        if (B % 2 != 0) {
            b += 1;
        }
        int lq = A - a / 2;
        int rq = A + a / 2;
        int br = B - b / 2;
        int tr = B + b / 2;
        for (int i = lq; i < rq + 1; i++) {
            neighbors.add(new Tuple(i, br));
            neighbors.add(new Tuple(i, tr));

        }
        for (int i = br + 1; i < tr; i++) {
            neighbors.add(new Tuple(lq, i));
            neighbors.add(new Tuple(rq, i));

        }
        return neighbors;

    }

    public String tabuSearch(Integer... params) {
        NumberFormat f = NumberFormat.getCurrencyInstance();
        String res = "";
        int A = params.length > 0 ? params[0] > 0 ? params[0] : model.getA() : model.getA();
        int B = params.length > 1 ? params[1] > 0 ? params[1] : model.getB() : model.getB();
        Tuple.nameA = model.getNameA();
        Tuple.nameB = model.getNameB();
        tabuList.add(new Tuple(A, B));
        MersenneTwisterFast rng = new MersenneTwisterFast();
        Tuple answer = new Tuple(A, B);
        double minCost = model.costFunction();
        res += "Solucion Inicial = " + answer + " con funcion de costo = " + f.format(minCost) + "\n";
        ArrayList<Tuple> neighbors = Neighbors(A, B);
        for (int i = 0; i < neighbors.size(); i++) {
            int pos = rng.nextInt(neighbors.size());
            Tuple current = neighbors.get(pos);
            if (!tabuList.contains(current)) {
                tabuList.add(current);
                model.setA(current.getA());
                model.setB(current.getB());
                double estimateCost = model.costFunction();
                if (minCost > estimateCost) {
                    minCost = estimateCost;
                    answer = current;
                } else {
                    model.setA(answer.getA());
                    model.setB(answer.getB());
                }
            } else {
                //System.out.println("Already in list");
            }
        }
        //TODO Display answer
        res += "Solucion Optima encontrada = " + answer + " con funcion de costo = " + f.format(minCost);
        return res;
    }
}
